#include "common/runtime/Hash.hpp"
#include "vectorwise/Operations.hpp"
#include "vectorwise/Primitives.hpp"
#include <functional>

using namespace types;
using namespace std;

namespace vectorwise {
namespace primitives {

#define MK_AGGR_STATIC_COL(type, op)                                           \
   F2 aggr_static_##op##_##type##_col = (F2)&aggr_static_col<type, op>;

#define MK_AGGR_STATIC_SEL_COL(type, op)                                       \
   F3 aggr_static_sel_##op##_##type##_col = (F3)&aggr_static_sel_col<type, op>;
#define MK_AGGR_COL(type, op)                                                  \
   FAggr aggr_##op##_##type##_col = (FAggr)&aggr_col<type, op>;
#define MK_AGGR_SEL_COL(type, op)                                              \
   FAggrSel aggr_sel_##op##_##type##_col = (FAggrSel)&aggr_sel_col<type, op>;
#define MK_AGGR_ROW(type, op)                                                  \
   FAggrRow aggr_row_##op##_##type##_col = (FAggrRow)&aggr_row<type, op>;
#define MK_AGGR_INIT(type, op)                                                 \
   FAggrInit aggr_init_##op##_##type##_col = (FAggrInit)&aggr_init<type, op>;

pos_t aggr_static_count_star_(pos_t n, int64_t* RES result)
/// aggregate column
{
   *result += n;
   return n > 0;
}
F1 aggr_static_count_star = (F1)&aggr_static_count_star_;

pos_t aggr_count_star_(pos_t n, int64_t* RES entries[], void* RES /*param1*/,
                       size_t offset)
/// update count aggregates for each entry pointed to by entries
{
   for (uint64_t i = 0; i < n; ++i) {
      auto aggregate = addBytes(entries[i], offset);
      *aggregate += 1;
   }
   return n;
}
FAggr aggr_count_star = (FAggr)&aggr_count_star_;

//EACH_ARITH(EACH_TYPE_FULL, MK_AGGR_STATIC_COL)
F2 aggr_static_plus_int32_t_col = (F2)&aggr_static_col<int32_t, plus>;
F2 aggr_static_plus_int64_t_col = (F2)&aggr_static_col<int64_t, plus>;
F2 aggr_static_plus_int8_t_col = (F2)&aggr_static_col<int8_t, plus>;
F2 aggr_static_plus_int16_t_col = (F2)&aggr_static_col<int16_t, plus>;
F2 aggr_static_multiplies_int32_t_col =
    (F2)&aggr_static_col<int32_t, multiplies>;
F2 aggr_static_multiplies_int64_t_col =
    (F2)&aggr_static_col<int64_t, multiplies>;
F2 aggr_static_multiplies_int8_t_col = (F2)&aggr_static_col<int8_t, multiplies>;
F2 aggr_static_multiplies_int16_t_col =
    (F2)&aggr_static_col<int16_t, multiplies>;
F2 aggr_static_minus_int32_t_col = (F2)&aggr_static_col<int32_t, minus>;
F2 aggr_static_minus_int64_t_col = (F2)&aggr_static_col<int64_t, minus>;
F2 aggr_static_minus_int8_t_col = (F2)&aggr_static_col<int8_t, minus>;
F2 aggr_static_minus_int16_t_col = (F2)&aggr_static_col<int16_t, minus>;
F2 aggr_static_divides_int32_t_col = (F2)&aggr_static_col<int32_t, divides>;
F2 aggr_static_divides_int64_t_col = (F2)&aggr_static_col<int64_t, divides>;
F2 aggr_static_divides_int8_t_col = (F2)&aggr_static_col<int8_t, divides>;
F2 aggr_static_divides_int16_t_col = (F2)&aggr_static_col<int16_t, divides>;
F2 aggr_static_modulus_int32_t_col = (F2)&aggr_static_col<int32_t, modulus>;
F2 aggr_static_modulus_int64_t_col = (F2)&aggr_static_col<int64_t, modulus>;
F2 aggr_static_modulus_int8_t_col = (F2)&aggr_static_col<int8_t, modulus>;
F2 aggr_static_modulus_int16_t_col = (F2)&aggr_static_col<int16_t, modulus>;

//EACH_ARITH(EACH_TYPE_FULL, MK_AGGR_STATIC_SEL_COL)
F3 aggr_static_sel_plus_int32_t_col = (F3)&aggr_static_sel_col<int32_t, plus>;
F3 aggr_static_sel_plus_int64_t_col = (F3)&aggr_static_sel_col<int64_t, plus>;
F3 aggr_static_sel_plus_int8_t_col = (F3)&aggr_static_sel_col<int8_t, plus>;
F3 aggr_static_sel_plus_int16_t_col = (F3)&aggr_static_sel_col<int16_t, plus>;
F3 aggr_static_sel_multiplies_int32_t_col =
    (F3)&aggr_static_sel_col<int32_t, multiplies>;
F3 aggr_static_sel_multiplies_int64_t_col =
    (F3)&aggr_static_sel_col<int64_t, multiplies>;
F3 aggr_static_sel_multiplies_int8_t_col =
    (F3)&aggr_static_sel_col<int8_t, multiplies>;
F3 aggr_static_sel_multiplies_int16_t_col =
    (F3)&aggr_static_sel_col<int16_t, multiplies>;
F3 aggr_static_sel_minus_int32_t_col = (F3)&aggr_static_sel_col<int32_t, minus>;
F3 aggr_static_sel_minus_int64_t_col = (F3)&aggr_static_sel_col<int64_t, minus>;
F3 aggr_static_sel_minus_int8_t_col = (F3)&aggr_static_sel_col<int8_t, minus>;
F3 aggr_static_sel_minus_int16_t_col = (F3)&aggr_static_sel_col<int16_t, minus>;
F3 aggr_static_sel_divides_int32_t_col =
    (F3)&aggr_static_sel_col<int32_t, divides>;
F3 aggr_static_sel_divides_int64_t_col =
    (F3)&aggr_static_sel_col<int64_t, divides>;
F3 aggr_static_sel_divides_int8_t_col =
    (F3)&aggr_static_sel_col<int8_t, divides>;
F3 aggr_static_sel_divides_int16_t_col =
    (F3)&aggr_static_sel_col<int16_t, divides>;
F3 aggr_static_sel_modulus_int32_t_col =
    (F3)&aggr_static_sel_col<int32_t, modulus>;
F3 aggr_static_sel_modulus_int64_t_col =
    (F3)&aggr_static_sel_col<int64_t, modulus>;
F3 aggr_static_sel_modulus_int8_t_col =
    (F3)&aggr_static_sel_col<int8_t, modulus>;
F3 aggr_static_sel_modulus_int16_t_col =
    (F3)&aggr_static_sel_col<int16_t, modulus>;

//EACH_ARITH(EACH_TYPE_FULL, MK_AGGR_COL)
FAggr aggr_plus_int32_t_col = (FAggr)&aggr_col<int32_t, plus>;
FAggr aggr_plus_int64_t_col = (FAggr)&aggr_col<int64_t, plus>;
FAggr aggr_plus_int8_t_col = (FAggr)&aggr_col<int8_t, plus>;
FAggr aggr_plus_int16_t_col = (FAggr)&aggr_col<int16_t, plus>;
FAggr aggr_multiplies_int32_t_col = (FAggr)&aggr_col<int32_t, multiplies>;
FAggr aggr_multiplies_int64_t_col = (FAggr)&aggr_col<int64_t, multiplies>;
FAggr aggr_multiplies_int8_t_col = (FAggr)&aggr_col<int8_t, multiplies>;
FAggr aggr_multiplies_int16_t_col = (FAggr)&aggr_col<int16_t, multiplies>;
FAggr aggr_minus_int32_t_col = (FAggr)&aggr_col<int32_t, minus>;
FAggr aggr_minus_int64_t_col = (FAggr)&aggr_col<int64_t, minus>;
FAggr aggr_minus_int8_t_col = (FAggr)&aggr_col<int8_t, minus>;
FAggr aggr_minus_int16_t_col = (FAggr)&aggr_col<int16_t, minus>;
FAggr aggr_divides_int32_t_col = (FAggr)&aggr_col<int32_t, divides>;
FAggr aggr_divides_int64_t_col = (FAggr)&aggr_col<int64_t, divides>;
FAggr aggr_divides_int8_t_col = (FAggr)&aggr_col<int8_t, divides>;
FAggr aggr_divides_int16_t_col = (FAggr)&aggr_col<int16_t, divides>;
FAggr aggr_modulus_int32_t_col = (FAggr)&aggr_col<int32_t, modulus>;
FAggr aggr_modulus_int64_t_col = (FAggr)&aggr_col<int64_t, modulus>;
FAggr aggr_modulus_int8_t_col = (FAggr)&aggr_col<int8_t, modulus>;
FAggr aggr_modulus_int16_t_col = (FAggr)&aggr_col<int16_t, modulus>;

//EACH_ARITH(EACH_TYPE_FULL, MK_AGGR_SEL_COL)
FAggrSel aggr_sel_plus_int32_t_col = (FAggrSel)&aggr_sel_col<int32_t, plus>;
FAggrSel aggr_sel_plus_int64_t_col = (FAggrSel)&aggr_sel_col<int64_t, plus>;
FAggrSel aggr_sel_plus_int8_t_col = (FAggrSel)&aggr_sel_col<int8_t, plus>;
FAggrSel aggr_sel_plus_int16_t_col = (FAggrSel)&aggr_sel_col<int16_t, plus>;
FAggrSel aggr_sel_multiplies_int32_t_col =
    (FAggrSel)&aggr_sel_col<int32_t, multiplies>;
FAggrSel aggr_sel_multiplies_int64_t_col =
    (FAggrSel)&aggr_sel_col<int64_t, multiplies>;
FAggrSel aggr_sel_multiplies_int8_t_col =
    (FAggrSel)&aggr_sel_col<int8_t, multiplies>;
FAggrSel aggr_sel_multiplies_int16_t_col =
    (FAggrSel)&aggr_sel_col<int16_t, multiplies>;
FAggrSel aggr_sel_minus_int32_t_col = (FAggrSel)&aggr_sel_col<int32_t, minus>;
FAggrSel aggr_sel_minus_int64_t_col = (FAggrSel)&aggr_sel_col<int64_t, minus>;
FAggrSel aggr_sel_minus_int8_t_col = (FAggrSel)&aggr_sel_col<int8_t, minus>;
FAggrSel aggr_sel_minus_int16_t_col = (FAggrSel)&aggr_sel_col<int16_t, minus>;
FAggrSel aggr_sel_divides_int32_t_col =
    (FAggrSel)&aggr_sel_col<int32_t, divides>;
FAggrSel aggr_sel_divides_int64_t_col =
    (FAggrSel)&aggr_sel_col<int64_t, divides>;
FAggrSel aggr_sel_divides_int8_t_col = (FAggrSel)&aggr_sel_col<int8_t, divides>;
FAggrSel aggr_sel_divides_int16_t_col =
    (FAggrSel)&aggr_sel_col<int16_t, divides>;
FAggrSel aggr_sel_modulus_int32_t_col =
    (FAggrSel)&aggr_sel_col<int32_t, modulus>;
FAggrSel aggr_sel_modulus_int64_t_col =
    (FAggrSel)&aggr_sel_col<int64_t, modulus>;
FAggrSel aggr_sel_modulus_int8_t_col = (FAggrSel)&aggr_sel_col<int8_t, modulus>;
FAggrSel aggr_sel_modulus_int16_t_col =
    (FAggrSel)&aggr_sel_col<int16_t, modulus>;

//EACH_ARITH(EACH_TYPE_FULL, MK_AGGR_ROW)
FAggrRow aggr_row_plus_int32_t_col = (FAggrRow)&aggr_row<int32_t, plus>;
FAggrRow aggr_row_plus_int64_t_col = (FAggrRow)&aggr_row<int64_t, plus>;
FAggrRow aggr_row_plus_int8_t_col = (FAggrRow)&aggr_row<int8_t, plus>;
FAggrRow aggr_row_plus_int16_t_col = (FAggrRow)&aggr_row<int16_t, plus>;
FAggrRow aggr_row_multiplies_int32_t_col =
    (FAggrRow)&aggr_row<int32_t, multiplies>;
FAggrRow aggr_row_multiplies_int64_t_col =
    (FAggrRow)&aggr_row<int64_t, multiplies>;
FAggrRow aggr_row_multiplies_int8_t_col =
    (FAggrRow)&aggr_row<int8_t, multiplies>;
FAggrRow aggr_row_multiplies_int16_t_col =
    (FAggrRow)&aggr_row<int16_t, multiplies>;
FAggrRow aggr_row_minus_int32_t_col = (FAggrRow)&aggr_row<int32_t, minus>;
FAggrRow aggr_row_minus_int64_t_col = (FAggrRow)&aggr_row<int64_t, minus>;
FAggrRow aggr_row_minus_int8_t_col = (FAggrRow)&aggr_row<int8_t, minus>;
FAggrRow aggr_row_minus_int16_t_col = (FAggrRow)&aggr_row<int16_t, minus>;
FAggrRow aggr_row_divides_int32_t_col = (FAggrRow)&aggr_row<int32_t, divides>;
FAggrRow aggr_row_divides_int64_t_col = (FAggrRow)&aggr_row<int64_t, divides>;
FAggrRow aggr_row_divides_int8_t_col = (FAggrRow)&aggr_row<int8_t, divides>;
FAggrRow aggr_row_divides_int16_t_col = (FAggrRow)&aggr_row<int16_t, divides>;
FAggrRow aggr_row_modulus_int32_t_col = (FAggrRow)&aggr_row<int32_t, modulus>;
FAggrRow aggr_row_modulus_int64_t_col = (FAggrRow)&aggr_row<int64_t, modulus>;
FAggrRow aggr_row_modulus_int8_t_col = (FAggrRow)&aggr_row<int8_t, modulus>;
FAggrRow aggr_row_modulus_int16_t_col = (FAggrRow)&aggr_row<int16_t, modulus>;

//EACH_ARITH(EACH_TYPE_FULL, MK_AGGR_INIT)
FAggrInit aggr_init_plus_int32_t_col = (FAggrInit)&aggr_init<int32_t, plus>;
FAggrInit aggr_init_plus_int64_t_col = (FAggrInit)&aggr_init<int64_t, plus>;
FAggrInit aggr_init_plus_int8_t_col = (FAggrInit)&aggr_init<int8_t, plus>;
FAggrInit aggr_init_plus_int16_t_col = (FAggrInit)&aggr_init<int16_t, plus>;
FAggrInit aggr_init_multiplies_int32_t_col =
    (FAggrInit)&aggr_init<int32_t, multiplies>;
FAggrInit aggr_init_multiplies_int64_t_col =
    (FAggrInit)&aggr_init<int64_t, multiplies>;
FAggrInit aggr_init_multiplies_int8_t_col =
    (FAggrInit)&aggr_init<int8_t, multiplies>;
FAggrInit aggr_init_multiplies_int16_t_col =
    (FAggrInit)&aggr_init<int16_t, multiplies>;
FAggrInit aggr_init_minus_int32_t_col = (FAggrInit)&aggr_init<int32_t, minus>;
FAggrInit aggr_init_minus_int64_t_col = (FAggrInit)&aggr_init<int64_t, minus>;
FAggrInit aggr_init_minus_int8_t_col = (FAggrInit)&aggr_init<int8_t, minus>;
FAggrInit aggr_init_minus_int16_t_col = (FAggrInit)&aggr_init<int16_t, minus>;
FAggrInit aggr_init_divides_int32_t_col =
    (FAggrInit)&aggr_init<int32_t, divides>;
FAggrInit aggr_init_divides_int64_t_col =
    (FAggrInit)&aggr_init<int64_t, divides>;
FAggrInit aggr_init_divides_int8_t_col = (FAggrInit)&aggr_init<int8_t, divides>;
FAggrInit aggr_init_divides_int16_t_col =
    (FAggrInit)&aggr_init<int16_t, divides>;
FAggrInit aggr_init_modulus_int32_t_col =
    (FAggrInit)&aggr_init<int32_t, modulus>;
FAggrInit aggr_init_modulus_int64_t_col =
    (FAggrInit)&aggr_init<int64_t, modulus>;
FAggrInit aggr_init_modulus_int8_t_col = (FAggrInit)&aggr_init<int8_t, modulus>;
FAggrInit aggr_init_modulus_int16_t_col =
    (FAggrInit)&aggr_init<int16_t, modulus>;
}
}
